package com.weixinpay.impl;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Response;

import org.springframework.stereotype.Service;

import com.orangelife.setting.constant.CodeConst;
import com.orangelife.utils.MD5Util;
import com.orangelife.utils.ProConfig;
import com.orangelife.utils.StringUtils;
import com.orangelife.webservice.base.BaseService;
import com.weixinpay.IWeiXinPayWebService;
import com.weixinpay.utils.GetWxOrderno;
import com.weixinpay.utils.Sha1Util;
import com.weixinpay.utils.TenpayUtil;

/*****************************************************************
 * Copyright(C) ORANGELIFE Corporation 2015. All Rights Reserved.
 *****************************************************************/
/*
 * ============================================================== 功能名 payOrder类
 * 的WebService基本作业
 * 
 * @author zhr
 * 
 * @version 1.1.0
 * 
 * @date 2015-09-23 19:28:39
 * ==============================================================
 */
@Service("WeiXinPayWebService")
public class WeiXinPayWebServiceImpl extends BaseService implements
		IWeiXinPayWebService {

	/**
	 * 
	 */
	@SuppressWarnings("unused")
	private static final long serialVersionUID = 1L;

	public static String toXml(Map<String, String> params) {
		StringBuilder sb = new StringBuilder();
		sb.append("<xml>");

		for (String key : params.keySet()) {
			sb.append("<" + key + ">");
			sb.append(params.get(key));
			sb.append("</" + key + ">");
		}

		sb.append("</xml>");
		return sb.toString();

	}

	public static String MaPtoXml(Map<String, Object> params) {
		StringBuilder sb = new StringBuilder();
		sb.append("<xml>");

		for (String key : params.keySet()) {
			sb.append("<" + key + ">");
			sb.append(params.get(key));
			sb.append("</" + key + ">");
		}

		sb.append("</xml>");
		return sb.toString();

	}

	/**
	 * 获取随机字符串
	 * 
	 * @return
	 */
	public static String getNonceStr() {
		// 随机数
		String currTime = TenpayUtil.getCurrTime();
		// 8位日期
		String strTime = currTime.substring(8, currTime.length());
		// 四位随机数
		String strRandom = TenpayUtil.buildRandom(4) + "";
		// 10位序列号,可以自行调整。
		return strTime + strRandom;
	}

	/**
	 * 生成签名
	 */

	private String genPackageSign(Map<String, String> params, String partnerkey) {
		StringBuilder sb = new StringBuilder();

		for (String key : params.keySet()) {
			sb.append(key);
			sb.append('=');
			sb.append(params.get(key));
			sb.append('&');
		}
		sb.append("key=");
		sb.append(partnerkey);

		String packageSign = MD5Util.MD5Encoder(sb.toString(), "UTF-8")
				.toUpperCase();
		return packageSign;
	}

	private String genAppSign(Map<String, String> params, String partnerkey) {
		StringBuilder sb = new StringBuilder();

		for (String key : params.keySet()) {
			sb.append(key);
			sb.append('=');
			sb.append(params.get(key));
			sb.append('&');
		}
		sb.append("key=");
		sb.append(partnerkey);

		// this.sb.append("sign str\n" + sb.toString() + "\n\n");
		String appSign = MD5Util.MD5Encoder(sb.toString(), "UTF-8")
				.toUpperCase();
		return appSign;
	}

	@Override
	public Response weiXinJsPayRequest(HttpServletRequest servletRequest,
			HttpServletResponse servletResponse, String openID, String body,
			String detail, String out_trade_no, String total_fee,
			String spbill_create_ip, String trade_type) throws Exception {

		Map<String, String> resInfo = new HashMap<String, String>();

		Response error = this.validateOrderID(out_trade_no, "支付流水");
		if (error != null) {
			return error;
		}

		error = this.validateMoney(total_fee, "商品金额");
		if (error != null) {
			return error;
		}
		BigDecimal totalFee = new BigDecimal(total_fee);
		total_fee = totalFee.multiply(new BigDecimal("100")).intValue() + "";

		error = this.validateLength(body, "商品描述", 16);
		if (error != null) {
			return error;
		}

		if (!StringUtils.isBlank(detail)) {
			error = this.validateLength(detail, "商品详情", 4096);
			if (error != null) {
				return error;
			}
		} else {
			detail = "";
		}

		error = this.validateLength(spbill_create_ip, "spbill_create_ip", 16);
		if (error != null) {
			return error;
		}

		error = this.validateLength(trade_type, "trade_type", 8);
		if (error != null) {
			return error;
		}

		String nonce_str = getNonceStr();

		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		String appid = ProConfig.getProValues("WXAPPID");
		String mch_id = ProConfig.getProValues("WXMERCHANT");
		String partnerkey = ProConfig.getProValues("WXPARTNERKEY");
		// 注意：这里的参数必须按ASCII编码排序，否则会导致生成的签名与服务器不同，导致签名错误
		packageParams.put("appid", appid);
		packageParams.put("body", body);
		if (!StringUtils.isBlank(detail)) {
			packageParams.put("detail", detail);
		}

		packageParams.put("mch_id", mch_id);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("notify_url",
				ProConfig.getProValues("SVC_WEI_XIN_NOTIFY"));
		packageParams.put("out_trade_no", out_trade_no);
		packageParams.put("spbill_create_ip", spbill_create_ip);
		packageParams.put("total_fee", total_fee);
		packageParams.put("trade_type", trade_type);

		packageParams.put("openid", openID);
		// RequestHandler reqHandler = new RequestHandler(null, null);
		// reqHandler.init(null, null, partnerkey);
		//
		// String sign = reqHandler.createSign(packageParams);
		String sign = genPackageSign(packageParams, partnerkey);
		packageParams.put("sign", sign);
		String xmlstring = toXml(packageParams);
		System.out.println(xmlstring);

		String xml = xmlstring;
		System.out.println(xml);
		String prepay_id = "";
		String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

		prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);
		if (StringUtils.isBlank(prepay_id)) {
			return this.abnormalResp(CodeConst.BUSINESS, "生成预支付ID失败");
		}
		String timestamp = Sha1Util.getTimeStamp();

		Map<String, String> signParams = new LinkedHashMap<String, String>();
		signParams.put("appId", appid);
		signParams.put("nonceStr", nonce_str);
		// signParams.put("package", "Sign=WXPay");
		// signParams.put("partnerid", mch_id);

		signParams.put("package", "Sign=WXPay");
		signParams.put("package", "prepay_id=" + prepay_id);
		signParams.put("timeStamp", timestamp);
		signParams.put("signType", "MD5");

		String sign1 = genAppSign(this.getPostMap(signParams), partnerkey);
		System.out.println(sign1);

		resInfo.put("appID", appid);
		resInfo.put("timeStamp", timestamp);
		resInfo.put("nonceStr", nonce_str);
		resInfo.put("packageName", "Sign=WXPay");
		resInfo.put("signType", "MD5");
		resInfo.put("partner", mch_id);
		resInfo.put("prepayID", prepay_id);
		resInfo.put("sign", sign1);

		return this.normalResp(resInfo);
	}

	@Override
	public Map<String, String> weiXinJsPayJsp(String openID, String body,
			String detail, String out_trade_no, String total_fee,
			String spbill_create_ip, String trade_type) throws Exception {

		Map<String, String> resInfo = new HashMap<String, String>();

		/*
		 * Date date = new Date(); System.out.println(date.getTime());
		 */
		Response error = this.validateOrderID(out_trade_no, "支付流水");
		if (error != null) {
			resInfo.put("error", "出错");
			return resInfo;
		}

		error = this.validateMoney(total_fee, "商品金额");
		if (error != null) {
			resInfo.put("error", "出错");
			return resInfo;
		}
		BigDecimal totalFee = new BigDecimal(total_fee);
		total_fee = totalFee.multiply(new BigDecimal("100")).intValue() + "";

		error = this.validateLength(body, "商品描述", 16);
		if (error != null) {
			resInfo.put("error", "出错");
			return resInfo;
		}

		if (!StringUtils.isBlank(detail)) {
			error = this.validateLength(detail, "商品详情", 4096);
			if (error != null) {
				resInfo.put("error", "出错");
				return resInfo;
			}
		} else {
			detail = "";
		}

		error = this.validateLength(spbill_create_ip, "spbill_create_ip", 16);
		if (error != null) {
			resInfo.put("error", "出错");
			return resInfo;
		}

		error = this.validateLength(trade_type, "trade_type", 8);
		if (error != null) {
			resInfo.put("error", "出错");
			return resInfo;
		}

		String nonce_str = getNonceStr();

		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		String appid = ProConfig.getProValues("WXAPPID");
		String mch_id = ProConfig.getProValues("WXMERCHANT");
		String partnerkey = ProConfig.getProValues("WXPARTNERKEY");
		// 注意：这里的参数必须按ASCII编码排序，否则会导致生成的签名与服务器不同，导致签名错误
		packageParams.put("appid", appid);
		packageParams.put("body", body);
		if (!StringUtils.isBlank(detail)) {
			packageParams.put("detail", detail);
		}

		packageParams.put("mch_id", mch_id);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("notify_url",
				ProConfig.getProValues("SVC_WEI_XIN_NOTIFY"));
		packageParams.put("out_trade_no", out_trade_no);
		packageParams.put("spbill_create_ip", spbill_create_ip);
		packageParams.put("total_fee", total_fee);
		packageParams.put("trade_type", trade_type);

		packageParams.put("openid", openID);
		// RequestHandler reqHandler = new RequestHandler(null, null);
		// reqHandler.init(null, null, partnerkey);
		//
		// String sign = reqHandler.createSign(packageParams);
		String sign = genPackageSign(packageParams, partnerkey);
		packageParams.put("sign", sign);
		String xmlstring = toXml(packageParams);
		System.out.println(xmlstring);

		String xml = xmlstring;
		System.out.println(xml);
		String prepay_id = "";
		String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

		prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);
		if (StringUtils.isBlank(prepay_id)) {
			resInfo.put("error", "出错");
			return resInfo;
		}
		String timestamp = Sha1Util.getTimeStamp();

		Map<String, String> signParams = new LinkedHashMap<String, String>();
		signParams.put("appId", appid);
		signParams.put("nonceStr", nonce_str);
		// signParams.put("package", "Sign=WXPay");
		// signParams.put("partnerid", mch_id);

		signParams.put("package", "Sign=WXPay");
		signParams.put("package", "prepay_id=" + prepay_id);
		signParams.put("timeStamp", timestamp);
		signParams.put("signType", "MD5");

		String sign1 = genAppSign(this.getPostMap(signParams), partnerkey);
		System.out.println(sign1);

		resInfo.put("appID", appid);
		resInfo.put("timeStamp", timestamp);
		resInfo.put("nonceStr", nonce_str);
		resInfo.put("packageName", "Sign=WXPay");
		resInfo.put("signType", "MD5");
		resInfo.put("partner", mch_id);
		resInfo.put("prepayID", prepay_id);
		resInfo.put("sign", sign1);

		return resInfo;
	}

	public Map<String, String> getPostMap(Map<String, String> paMap) {
		Map<String, String> map = new TreeMap<String, String>(
				new Comparator<String>() {
					public int compare(String firstKey, String secTkey) {
						// 升序序排序
						return firstKey.compareTo(secTkey);
					}
				});
		for (Entry<String, String> entry : paMap.entrySet()) {
			map.put(entry.getKey(), entry.getValue());
		}

		return map;
	}
}
